package com.kmxd.ams.core.mybatisplus.extend;

import com.baomidou.mybatisplus.core.toolkit.PluginUtils;
import com.baomidou.mybatisplus.extension.parser.JsqlParserSupport;
import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor;
import java.sql.Connection;
import java.sql.SQLException;
import lombok.extern.slf4j.Slf4j;
import net.sf.jsqlparser.JSQLParserException;
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
import net.sf.jsqlparser.statement.Statement;
import net.sf.jsqlparser.statement.insert.Insert;
import net.sf.jsqlparser.statement.select.FromItem;
import net.sf.jsqlparser.statement.select.PlainSelect;
import net.sf.jsqlparser.statement.select.Select;
import net.sf.jsqlparser.statement.select.SelectBody;
import net.sf.jsqlparser.statement.select.SetOperationList;
import net.sf.jsqlparser.statement.select.WithItem;
import net.sf.jsqlparser.statement.update.Update;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;

/**
 * @author 动态条件
 */
@Slf4j
public class DynamicFieldInterceptor extends JsqlParserSupport implements InnerInterceptor {

  @Override
  public void beforeQuery(
      Executor executor,
      MappedStatement ms,
      Object parameter,
      RowBounds rowBounds,
      ResultHandler resultHandler,
      BoundSql boundSql)
      throws SQLException {
    PluginUtils.MPBoundSql mpBs = PluginUtils.mpBoundSql(boundSql);
    mpBs.sql(this.changeSql(mpBs.sql()));
  }

  @Override
  public void beforePrepare(
      StatementHandler sh, Connection connection, Integer transactionTimeout) {
    PluginUtils.MPStatementHandler mpSh = PluginUtils.mpStatementHandler(sh);
    MappedStatement ms = mpSh.mappedStatement();
    SqlCommandType sct = ms.getSqlCommandType();
    if (sct == SqlCommandType.UPDATE || sct == SqlCommandType.DELETE) {
      PluginUtils.MPBoundSql mpBs = mpSh.mPBoundSql();
      mpBs.sql(this.changeSql(mpBs.sql()));
    }
  }

  protected String changeSql(String sql) {

    try {
      Statement statement = CCJSqlParserUtil.parse(sql);
      return processParser(statement, 0, sql, null);
    } catch (JSQLParserException ignore) {
    }
    return sql;
  }

  @Override
  protected void processInsert(Insert insert, int index, String sql, Object obj) {
    // 无需操作
      log.info("=================");
  }

  @Override
  protected void processUpdate(Update update, int index, String sql, Object obj) {}

  @Override
  protected void processSelect(Select select, int index, String sql, Object obj) {
    processSelectBody(select.getSelectBody());
  }

  private void processSelectBody(SelectBody selectBody) {
    if (selectBody instanceof PlainSelect) {
      processPlainSelect((PlainSelect) selectBody);
    } else if (selectBody instanceof WithItem) {
      WithItem withItem = (WithItem) selectBody;
      if (withItem.getSubSelect().getSelectBody() != null) {
        processSelectBody(withItem.getSubSelect().getSelectBody());
      }
    } else {
      SetOperationList operationList = (SetOperationList) selectBody;
      if (operationList.getSelects() != null && !operationList.getSelects().isEmpty()) {
        operationList.getSelects().forEach(this::processSelectBody);
      }
    }
  }

  private void processPlainSelect(PlainSelect plainSelect) {
    FromItem fromItem = plainSelect.getFromItem();
  }
}
